import * as fs from 'fs/promises';
import * as path from 'path';
import { LogConfig } from '../types';
import { LogFormatter } from '../utils/logFormatter';

export interface CleanupStats {
  totalFiles: number;
  deletedFiles: number;
  totalSizeBeforeCleanup: number;
  totalSizeAfterCleanup: number;
  oldestFileDate?: Date;
  newestFileDate?: Date;
}

export class LogCleanupService {
  private config: LogConfig;
  private logDirectory: string;
  private cleanupTimer: NodeJS.Timeout | null = null;
  private isRunning = false;

  constructor(config: LogConfig) {
    this.config = config;
    this.logDirectory = path.resolve(config.directory);
  }

  /**
   * 启动自动清理服务
   */
  start(): void {
    if (this.cleanupTimer) {
      console.warn('日志清理服务已经在运行中');
      return;
    }

    // 立即执行一次清理
    this.performCleanup().catch(error => {
      console.error('初始日志清理失败:', error);
    });

    // 设置定时清理（每天凌晨2点执行）
    this.scheduleNextCleanup();

    console.log('日志清理服务已启动');
  }

  /**
   * 停止自动清理服务
   */
  stop(): void {
    if (this.cleanupTimer) {
      clearTimeout(this.cleanupTimer);
      this.cleanupTimer = null;
    }

    console.log('日志清理服务已停止');
  }

  /**
   * 手动执行清理
   */
  async cleanup(): Promise<CleanupStats> {
    return await this.performCleanup();
  }

  /**
   * 获取日志目录统计信息
   */
  async getDirectoryStats(): Promise<{
    totalFiles: number;
    totalSize: number;
    oldestFile?: { name: string; date: Date };
    newestFile?: { name: string; date: Date };
    fileSizes: Array<{ name: string; size: number; date: Date }>;
  }> {
    try {
      const logFiles = await this.getLogFiles();
      
      if (logFiles.length === 0) {
        return {
          totalFiles: 0,
          totalSize: 0,
          fileSizes: []
        };
      }

      const fileInfos = await Promise.all(
        logFiles.map(async (filePath) => {
          const stats = await fs.stat(filePath);
          const fileName = path.basename(filePath);
          const date = LogFormatter.parseLogFileName(fileName);
          
          return {
            name: fileName,
            path: filePath,
            size: stats.size,
            date: date || stats.mtime
          };
        })
      );

      // 按日期排序
      fileInfos.sort((a, b) => a.date.getTime() - b.date.getTime());

      const totalSize = fileInfos.reduce((sum, info) => sum + info.size, 0);

      return {
        totalFiles: fileInfos.length,
        totalSize,
        oldestFile: fileInfos.length > 0 ? {
          name: fileInfos[0].name,
          date: fileInfos[0].date
        } : undefined,
        newestFile: fileInfos.length > 0 ? {
          name: fileInfos[fileInfos.length - 1].name,
          date: fileInfos[fileInfos.length - 1].date
        } : undefined,
        fileSizes: fileInfos.map(info => ({
          name: info.name,
          size: info.size,
          date: info.date
        }))
      };
    } catch (error) {
      console.error('获取目录统计信息失败:', error);
      throw error;
    }
  }

  /**
   * 检查是否需要清理
   */
  async needsCleanup(): Promise<{
    byCount: boolean;
    bySize: boolean;
    fileCount: number;
    totalSize: number;
  }> {
    const stats = await this.getDirectoryStats();
    
    // 检查文件数量是否超过限制
    const byCount = stats.totalFiles > this.config.maxFiles;
    
    // 检查总大小是否超过限制（如果配置了大小限制）
    const maxTotalSize = this.config.maxFileSize * this.config.maxFiles * 1024 * 1024;
    const bySize = stats.totalSize > maxTotalSize;

    return {
      byCount,
      bySize,
      fileCount: stats.totalFiles,
      totalSize: stats.totalSize
    };
  }

  /**
   * 执行清理操作
   */
  private async performCleanup(): Promise<CleanupStats> {
    if (this.isRunning) {
      throw new Error('清理操作已在进行中');
    }

    this.isRunning = true;

    try {
      console.log('开始执行日志清理...');

      const beforeStats = await this.getDirectoryStats();
      const cleanupNeeded = await this.needsCleanup();

      if (!cleanupNeeded.byCount && !cleanupNeeded.bySize) {
        console.log('无需清理日志文件');
        return {
          totalFiles: beforeStats.totalFiles,
          deletedFiles: 0,
          totalSizeBeforeCleanup: beforeStats.totalSize,
          totalSizeAfterCleanup: beforeStats.totalSize,
          oldestFileDate: beforeStats.oldestFile?.date,
          newestFileDate: beforeStats.newestFile?.date
        };
      }

      // 获取所有日志文件并按时间排序
      const fileInfos = beforeStats.fileSizes.sort((a, b) => 
        a.date.getTime() - b.date.getTime()
      );

      const filesToDelete: string[] = [];

      // 按文件数量清理
      if (cleanupNeeded.byCount) {
        const excessCount = beforeStats.totalFiles - this.config.maxFiles;
        const oldestFiles = fileInfos.slice(0, excessCount);
        filesToDelete.push(...oldestFiles.map(info => 
          path.join(this.logDirectory, info.name)
        ));
      }

      // 按总大小清理（如果仍然需要）
      if (cleanupNeeded.bySize) {
        let currentSize = beforeStats.totalSize;
        const maxTotalSize = this.config.maxFileSize * this.config.maxFiles * 1024 * 1024;
        
        for (const fileInfo of fileInfos) {
          const filePath = path.join(this.logDirectory, fileInfo.name);
          
          if (!filesToDelete.includes(filePath) && currentSize > maxTotalSize) {
            filesToDelete.push(filePath);
            currentSize -= fileInfo.size;
          }
        }
      }

      // 删除文件
      let deletedCount = 0;
      for (const filePath of filesToDelete) {
        try {
          await this.deleteLogFile(filePath);
          deletedCount++;
          console.log(`已删除日志文件: ${path.basename(filePath)}`);
        } catch (error) {
          console.error(`删除文件失败 ${path.basename(filePath)}:`, error);
        }
      }

      // 清理空文件和损坏的文件
      const emptyFilesDeleted = await this.cleanupEmptyFiles();
      deletedCount += emptyFilesDeleted;

      const afterStats = await this.getDirectoryStats();

      const stats: CleanupStats = {
        totalFiles: beforeStats.totalFiles,
        deletedFiles: deletedCount,
        totalSizeBeforeCleanup: beforeStats.totalSize,
        totalSizeAfterCleanup: afterStats.totalSize,
        oldestFileDate: beforeStats.oldestFile?.date,
        newestFileDate: beforeStats.newestFile?.date
      };

      console.log(`日志清理完成: 删除了 ${deletedCount} 个文件, 释放空间 ${
        this.formatBytes(stats.totalSizeBeforeCleanup - stats.totalSizeAfterCleanup)
      }`);

      return stats;
    } finally {
      this.isRunning = false;
    }
  }

  /**
   * 删除空文件和损坏的文件
   */
  private async cleanupEmptyFiles(): Promise<number> {
    try {
      const logFiles = await this.getLogFiles();
      let deletedCount = 0;

      for (const filePath of logFiles) {
        try {
          const stats = await fs.stat(filePath);
          
          // 删除空文件
          if (stats.size === 0) {
            await this.deleteLogFile(filePath);
            deletedCount++;
            console.log(`已删除空文件: ${path.basename(filePath)}`);
            continue;
          }

          // 检查文件是否可读
          try {
            await fs.access(filePath, fs.constants.R_OK);
          } catch {
            await this.deleteLogFile(filePath);
            deletedCount++;
            console.log(`已删除不可读文件: ${path.basename(filePath)}`);
          }
        } catch (error) {
          console.warn(`检查文件失败 ${path.basename(filePath)}:`, error);
        }
      }

      return deletedCount;
    } catch (error) {
      console.error('清理空文件失败:', error);
      return 0;
    }
  }

  /**
   * 安全删除日志文件
   */
  private async deleteLogFile(filePath: string): Promise<void> {
    try {
      // 确保文件在日志目录内
      const resolvedPath = path.resolve(filePath);
      const resolvedLogDir = path.resolve(this.logDirectory);
      
      if (!resolvedPath.startsWith(resolvedLogDir)) {
        throw new Error('尝试删除日志目录外的文件');
      }

      // 确保是日志文件
      const fileName = path.basename(filePath);
      if (!fileName.match(/^cli-\d{4}-\d{2}-\d{2}-\d{2}\.log$/)) {
        throw new Error('不是有效的日志文件名');
      }

      await fs.unlink(filePath);
    } catch (error) {
      throw new Error(`删除文件失败: ${error}`);
    }
  }

  /**
   * 获取所有日志文件
   */
  private async getLogFiles(): Promise<string[]> {
    try {
      const files = await fs.readdir(this.logDirectory);
      return files
        .filter(file => file.match(/^cli-\d{4}-\d{2}-\d{2}-\d{2}\.log$/))
        .map(file => path.join(this.logDirectory, file));
    } catch (error) {
      console.error('读取日志目录失败:', error);
      return [];
    }
  }

  /**
   * 计算下次清理时间（每天凌晨2点）
   */
  private calculateNextCleanupTime(): Date {
    const now = new Date();
    const nextCleanup = new Date(now);
    
    // 设置为明天凌晨2点
    nextCleanup.setDate(nextCleanup.getDate() + 1);
    nextCleanup.setHours(2);
    nextCleanup.setMinutes(0);
    nextCleanup.setSeconds(0);
    nextCleanup.setMilliseconds(0);

    return nextCleanup;
  }

  /**
   * 安排下次清理
   */
  private scheduleNextCleanup(): void {
    const nextCleanupTime = this.calculateNextCleanupTime();
    const delay = nextCleanupTime.getTime() - Date.now();

    this.cleanupTimer = setTimeout(async () => {
      try {
        await this.performCleanup();
      } catch (error) {
        console.error('定时清理失败:', error);
      } finally {
        // 安排下一次清理
        this.scheduleNextCleanup();
      }
    }, delay);

    console.log(`下次日志清理时间: ${nextCleanupTime.toLocaleString()}`);
  }

  /**
   * 格式化字节数
   */
  private formatBytes(bytes: number): string {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * 检查清理服务状态
   */
  getStatus(): {
    isRunning: boolean;
    hasTimer: boolean;
    nextCleanupTime?: Date;
  } {
    const nextCleanupTime = this.cleanupTimer 
      ? this.calculateNextCleanupTime() 
      : undefined;

    return {
      isRunning: this.isRunning,
      hasTimer: this.cleanupTimer !== null,
      nextCleanupTime
    };
  }
}